package mx.vlabs.soapdroid.wsdl2java.artifactbuilder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import mx.vlabs.soapdroid.wsdl2java.Artifact;
import mx.vlabs.soapdroid.wsdl2java.ElementAttributes;
import mx.vlabs.soapdroid.wsdl2java.SDroidUtils;

import org.ow2.easywsdl.schema.api.ComplexType;
import org.ow2.easywsdl.schema.api.SimpleType;
import org.ow2.easywsdl.wsdl.api.InterfaceType;
import org.ow2.easywsdl.wsdl.api.Operation;
import org.ow2.easywsdl.wsdl.api.Part;

import static mx.vlabs.soapdroid.utils.Utils.*;

public class PortTypeArtifactBuilder extends ArtifactBuilder {
	
	private InterfaceType interfaceType;
	
	private boolean useWebParamImport = false;
	private boolean useWebResultImport = false;
	
	public PortTypeArtifactBuilder(InterfaceType interfaceType,String packageName){
		super(packageName);
		this.interfaceType = interfaceType;
	}

	@Override
	public String build() {
		// TODO Auto-generated method stub
		String portTypeNamespace = interfaceType.getQName().getNamespaceURI();
		String portTypeName      = interfaceType.getQName().getLocalPart();
		String portTypeClassName = capitalizeFirstLetter(portTypeName);
		
		getArtifact().setName(portTypeClassName);
		
		getArtifact().setParam("portTypeClassName", portTypeClassName);
		getArtifact().setParam("portTypeName", portTypeName);
		getArtifact().setParam("portTypeNamespace", portTypeNamespace);
		
		buildPortTypeOperations();
		
		if(useWebParamImport)
			getArtifact().setParam("webParamImport", "import mx.vlabs.soapdroid.annotations.WebParam;");
		else
			getArtifact().setParam("webParamImport", "");
		
		if(useWebResultImport)
			getArtifact().setParam("webResultImport", "import mx.vlabs.soapdroid.annotations.WebResult;");
		else
			getArtifact().setParam("webResultImport", "");
		
		return getArtifact().getContent();
	}
	
	private void buildPortTypeOperations(){
		
		StringBuilder sb = new StringBuilder();
		
		for(Operation operation:interfaceType.getOperations()){
			
				Artifact methodArtifact = getArtifactLoader().load("port.method", getArtifactType());
			
				
				methodArtifact.setParam("methodName", operation.getQName().getLocalPart());
				methodArtifact.setParam("packageName", getPackageName());
				
				buildOperationOutputArtifact(methodArtifact,operation);
				buildOperationInputArtifact(methodArtifact,operation);

				
				if(operation.getInput().getElement()!=null){
					methodArtifact.setParam("requestName", operation.getInput().getElement().getQName().getLocalPart());
					methodArtifact.setParam("requestNamespace", operation.getInput().getElement().getQName().getNamespaceURI());
					methodArtifact.setParam("requestClassName", capitalizeFirstLetter(operation.getInput().getElement().getQName().getLocalPart()));
				}else{
					methodArtifact.setParam("requestName","");
					methodArtifact.setParam("requestNamespace","");
					methodArtifact.setParam("requestClassName","");
				}
				
				if(operation.getOutput().getElement()!=null){
					methodArtifact.setParam("responseName", operation.getOutput().getElement().getQName().getLocalPart());
					methodArtifact.setParam("responseNamespace", operation.getOutput().getElement().getQName().getNamespaceURI());
					methodArtifact.setParam("responseClassName", capitalizeFirstLetter(operation.getOutput().getElement().getQName().getLocalPart()));
				}else{
					methodArtifact.setParam("responseName", "");
					methodArtifact.setParam("responseNamespace", "");
					methodArtifact.setParam("responseClassName", "");
				}
				
				sb.append(methodArtifact.getContent());
		}
		
		getArtifact().setParam("portTypeMethods", sb.toString());
		
	}
	
	private Artifact buildOperationOutputArtifact(Artifact methodArtifact,Operation operation){
		
		List<ElementAttributes> attrsList = null; 
		
		if(operation.getOutput().getElement()!=null)
			attrsList = ElementAttributes.explode(operation.getOutput().getElement().getType());
		else{
			attrsList = new ArrayList<ElementAttributes>();
			
			for(Part part : operation.getOutput().getParts()){
				attrsList.addAll(ElementAttributes.explode(part.getType()));
			}
		}
		
		if(attrsList.isEmpty()){
			methodArtifact.setParam("webResult", "");
			methodArtifact.setParam("returnType", "void");
		}else{
			
			useWebResultImport = true;
			
			for(ElementAttributes attrs : attrsList){
				String webResult = 
					getArtifactLoader().load("port.method.webresult",getArtifactType())
						.setParam("webResultName",((QName) attrs.get("name")).getLocalPart())
						.setParam("webResultNamespace", ((QName) attrs.get("name")).getNamespaceURI())
						.getContent();
				
				methodArtifact.setParam("webResult", webResult);
				methodArtifact.setParam("returnType", attrs.get("javaType").toString());
			}
			
		}
		
		return  methodArtifact;
	}
	
	private Artifact buildOperationInputArtifact(Artifact methodArtifact,Operation operation){

		List<ElementAttributes> attrsList = null;
		
		if(operation.getInput().getElement()!=null)
			attrsList = ElementAttributes.explode(operation.getInput().getElement().getType());
		else{
			attrsList = new ArrayList<ElementAttributes>();
			
			Map<QName, Integer> partsMap = new HashMap<QName, Integer>();
			
			for(Part part : operation.getInput().getParts()){
				
				ElementAttributes attrs = ElementAttributes.explodeSingle((SimpleType) part.getType());
				
				if(partsMap.containsKey(part.getType().getQName())){
					
					Integer nameCount = partsMap.get(part.getType().getQName());
					attrs.rename(part.getType().getQName().getLocalPart()+nameCount);
					
					partsMap.put(part.getType().getQName(), nameCount+1);
				}else{
					
					partsMap.put(part.getType().getQName(), 1);
					
				}
				
				attrsList.add(attrs);
			}
			
		}

		if(attrsList.isEmpty()){
			methodArtifact.setParam("methodArgs", "");
		}else{
			
			useWebParamImport = true;
			boolean firstRun = true;
			
			StringBuilder sb = new StringBuilder();
			
			for(ElementAttributes attrs : attrsList){
				
				String prefix = firstRun ? "" : ", ";
				
				if(firstRun) firstRun = false;
				
				String webParam = 
					getArtifactLoader().load("port.method.arg",getArtifactType())
						.setParam("methodArgName",((QName) attrs.get("name")).getLocalPart())
						.setParam("methodArgNamespace", ((QName) attrs.get("name")).getNamespaceURI())
						.setParam("methodArgType", attrs.get("javaType").toString())
						.setParam("methodJavaArgName", attrs.get("javaName").toString())
						.getContent();
				
				sb.append(prefix);
				sb.append(webParam);
			}
			
			methodArtifact.setParam("methodArgs",sb.toString());
			
		}
		
		return  methodArtifact;
	}
	

	@Override
	public String getArtifactType() {
		// TODO Auto-generated method stub
		return "port";
	}

}
